#include "sense_node.h"
#include "fpga_interface.h"

/**
 * @brief 启动一次检测
 *
 * @param level 门限，测试可以使用3000000
 */
void start_FFT_once(uint32_t level) {
    // 感知门限调整
    spi_write_fpga(1, 0x30, level & 0xFFFF);
    spi_write_fpga(1, 0x31, level >> 16);

    // Detect_en
    // 采用单片机控制扫频的方式进行工作，一次使能给出检测结果，检测结果写入RAM中，单片机从Page3读取相应数据，然后启动下一次FFT检测
    spi_write_fpga(1, 0x32, 0);
    spi_write_fpga(1, 0x32, 1);
    spi_write_fpga(1, 0x32, 0);
}

/**
 * @brief 读取信号数量
 *
 * @return uint16_t 信号数量
 */
uint16_t read_signal_number() {
    uint16_t fft_ram[4];
    for (int i = 0; i < 4; i++) {
        fft_ram[i] = spi_read_fpga(3, i);
    }
    uint16_t signal_num = *(uint64_t *)&fft_ram[0];

    return signal_num;
}

/**
 * @brief 读取检测结果
 *
 * @return uint16_t* 保存FFT结果的数组
 */
struct signal_in_fft_t *read_signal_val(uint16_t signal_num) {
    if (signal_num > MAX_SIGNAL_NUM) {
        signal_num = MAX_SIGNAL_NUM;
    }
    static struct signal_in_fft_t fft_signal[MAX_SIGNAL_NUM];
    uint16_t *ram = (uint16_t *)fft_signal;
    for (int i = 0; i < signal_num * sizeof(struct signal_in_fft_t) / sizeof(uint16_t); i++) {
        ram[i] = spi_read_fpga(3, i + 4);
    }
    return fft_signal;
}

/**
 * @brief 读取RAM
 *
 * @return uint16_t* 保存RAM的数组
 */
uint16_t *read_FFT_RAM() {
    static uint16_t fft_ram[FFT_RAM_SIZE];
    for (int i = 0; i < FFT_RAM_SIZE; i++) {
        fft_ram[i] = spi_read_fpga(3, i);
    }
    return fft_ram;
}

/**
 * @brief Get the FFT state object

 *
 * @return uint16_t
 * 1:检测已完成
 * 0:检测未完成但RAM已满
 * 如果RAM满了仍未检测完成，则表示信号太多，可以根据最大信号值调整门限
 */
uint16_t get_FFT_state() { return spi_read_fpga(1, 0x33); }

/**
 * @brief 启动数字下变频
 *
 * @param center_frequency
 * 中心频率值，中心频率值根据输入的信号来设定，参数设置的计算方法：65536-320*f，f表示需要产生的数字本振频率
 * @param band_sel 带宽选择参数 1：5K 2：25K 3：60K 4：200K 5：1.28M 6：6.4M`
 * @param channel 通道号，模块支持同时两路数字下变频并行处理
 */
void start_DDC(uint32_t center_frequency_kHz, uint16_t band_sel, uint16_t channel) {
    if (channel > 3)
        channel = 0;

    // 清除FIFO
    spi_write_fpga(0, 0x5, 2);
    uint16_t timeout = 32768;
    while (timeout > 0 && spi_read_fpga(0, 0x5)) {
        timeout--;
    }
    // 读清空历史报警
    spi_read_fpga(2, 0x31);
    spi_read_fpga(2, 0x33);

    uint16_t freq_code = 65536 - 32 * center_frequency_kHz / 100;
    spi_write_fpga(1, 0x08 + channel, freq_code);
    spi_write_fpga(1, 0x0c + channel, band_sel);
    spi_write_fpga(1, 0x10 + channel, 1);
}

/**
 * @brief 关闭数字下变频
 *
 * @param channel 通道号
 */
void stop_DDC(uint16_t channel) {
    if (channel > 3)
        channel = 0;
    spi_write_fpga(1, 0x10 + channel, 0);
    spi_write_fpga(1, 0x16 + channel, 0);
}

int16_t wait_DDC() {
    uint32_t timeout = 262144;
    while (timeout > 0 && (spi_read_fpga(2, 0x0b) != 0 || spi_read_fpga(2, 0x13) != 0)) {
        timeout--;
    }
    if (timeout == 0) {
        return -1;
    } else {
        return 0;
    }
}

/**
 * @brief 保存数字下变频的结果
 *
 * @param StoreLength_Ltime 存储时长
 * @param channel 通道号
 */
void store_DDC_result(uint32_t StoreLength_Ltime, uint32_t len, uint16_t channel) {
    if (channel > 1)
        channel = 0;

    if (channel == 0) {
        spi_write_fpga(1, 0x18, StoreLength_Ltime & 0xFFFF);
        spi_write_fpga(1, 0x19, StoreLength_Ltime >> 16);

        // RX通道1数据存储可用空间大小，单位为256bit，空间存满后，重新开始套圈
        spi_write_fpga(2, 0x09, len & 0xFFFF);
        spi_write_fpga(2, 0x0A, len >> 16);

        // RX通道1数据存储，长度单位为256bit，此值为0表示不间断存储，直到sp1wr_stop有效
        spi_write_fpga(2, 0x07, len & 0xFFFF);
        spi_write_fpga(2, 0x08, len >> 16);

        // 写入1开启一次RX通道1数据存储，存储过程结束后自动归0
        spi_write_fpga(2, 0x0b, 1);

        // RX通道1启动存储数据，写入1启动一次存储，存储时长为StoreLength_Ltime1
        spi_write_fpga(1, 0x16, 1);
    } else if (channel == 1) {
        spi_write_fpga(1, 0x1A, StoreLength_Ltime & 0xFFFF);
        spi_write_fpga(1, 0x1B, StoreLength_Ltime >> 16);

        //  RX通道2数据存储DDR起始地址，单位为256bit
        spi_write_fpga(2, 0x0D, 0x2000);
        spi_write_fpga(2, 0x0E, 0x0);

        // RX通道2数据存储可用空间大小，单位为256bit，空间存满后，重新开始套圈
        spi_write_fpga(2, 0x11, len & 0xFFFF);
        spi_write_fpga(2, 0x12, len >> 16);

        // RX通道2数据存储，长度单位为256bit，此值为0表示不间断存储，直到sp1wr_stop有效
        spi_write_fpga(2, 0x0F, len & 0xFFFF);
        spi_write_fpga(2, 0x10, len >> 16);

        // 写入1开启一次RX通道2数据存储，存储过程结束后自动归0
        spi_write_fpga(2, 0x13, 1);

        // RX通道2启动存储数据，写入1启动一次存储，存储时长为StoreLength_Ltime2
        spi_write_fpga(1, 0x17, 1);
    }
}

/**
 * @brief 设置时标
 *
 * @param min 分
 * @param sec 秒
 * @param day 日
 * @param hour 小时
 */
void set_timestamp(uint8_t min, uint8_t sec, uint8_t day, uint8_t hour) {
    spi_write_fpga(1, 0x15, day << 8 | hour);
    // 写秒的时候会刷新FPGA时间，所以更新秒放在第二行
    spi_write_fpga(1, 0x14, min << 8 | sec);
}

void read_start_time_ch1(uint8_t *day, uint8_t *hour, uint8_t *min, uint8_t *sec,
                         uint32_t *ns2048) {
    uint16_t val;
    val = spi_read_fpga(1, 0x21);
    *day = (val >> 8) & 0xff;
    *hour = val & 0xff;
    val = spi_read_fpga(1, 0x20);
    *min = (val >> 8) & 0xff;
    *sec = val & 0xff;

    val = spi_read_fpga(1, 0x29);
    *ns2048 = val;
    val = spi_read_fpga(1, 0x28);
    *ns2048 = (*ns2048 << 16) | val;
}

void read_end_time_ch1(uint8_t *day, uint8_t *hour, uint8_t *min, uint8_t *sec, uint32_t *ns2048) {
    uint16_t val;
    val = spi_read_fpga(1, 0x23);
    *day = (val >> 8) & 0xff;
    *hour = val & 0xff;
    val = spi_read_fpga(1, 0x22);
    *min = (val >> 8) & 0xff;
    *sec = val & 0xff;

    val = spi_read_fpga(1, 0x2B);
    *ns2048 = val;
    val = spi_read_fpga(1, 0x2A);
    *ns2048 = (*ns2048 << 16) | val;
}

void read_start_time_ch2(uint8_t *day, uint8_t *hour, uint8_t *min, uint8_t *sec,
                         uint32_t *ns2048) {
    uint16_t val;
    val = spi_read_fpga(1, 0x25);
    *day = (val >> 8) & 0xff;
    *hour = val & 0xff;
    val = spi_read_fpga(1, 0x24);
    *min = (val >> 8) & 0xff;
    *sec = val & 0xff;

    val = spi_read_fpga(1, 0x2D);
    *ns2048 = val;
    val = spi_read_fpga(1, 0x2C);
    *ns2048 = (*ns2048 << 16) | val;
}

void read_end_time_ch2(uint8_t *day, uint8_t *hour, uint8_t *min, uint8_t *sec, uint32_t *ns2048) {
    uint16_t val;
    val = spi_read_fpga(1, 0x27);
    *day = (val >> 8) & 0xff;
    *hour = val & 0xff;
    val = spi_read_fpga(1, 0x26);
    *min = (val >> 8) & 0xff;
    *sec = val & 0xff;

    val = spi_read_fpga(1, 0x2F);
    *ns2048 = val;
    val = spi_read_fpga(1, 0x2E);
    *ns2048 = (*ns2048 << 16) | val;
}
